<template>
    <!-- 基础表格组件 -->
    <el-table
        :ref="(el) => handleSetTableMap(el)"
        :id="props.tableId"
        :data="props.tableData"
        :height="props.tableHeight"
        :border="props.tableBorder"
        :fit="props.tableFit"
        :size="props.tableSize"
        :stripe="props.tableStripe"
        :tree-props="props.tableTreeProps"
        :row-key="props.tableRowKey"
        :highlight-current-row="props.tableHighlightCurrentRow"
        :loading="props.tableLoading"
        :default-expand-all="props.tableDefaultExpandAll"
        :row-class-name="props.tableRowClassName"
        :max-height="props.tableMaxHeight"
        :show-header="props.tableShowHeader"
        :current-row-key="props.tableCurrentRowKey"
        :row-style="props.tableRowStyle"
        :cell-class-name="props.tableCellClassName"
        :cell-style="props.tableCellStyle"
        :header-row-class-name="props.tableHeaderRowClassName"
        :header-row-style="props.tableHeaderRowStyle"
        :header-cell-class-name="props.tableHeaderCellClassName"
        :header-cell-style="props.tableHeaderCellStyle"
        :empty-text="props.tableEmptyText"
        :expand-row-keys="props.tableExpandRowKeys"
        :default-sort="props.tableDefaultSort"
        :tooltip-effect="props.tableTooltipEffect"
        :tooltip-options="props.tableTooltipOptions"
        :show-summary="props.tableShowSummary"
        :sum-text="props.tableSumText"
        :summary-method="props.tableSummaryMethod"
        :span-method="props.tableSpanMethod"
        :select-on-indeterminate="props.tableSelectOnIndeterminate"
        :indent="props.tableIndent"
        :lazy="props.tableLazy"
        :load="props.tableLoad"
        :table-layout="props.tableTableLayout"
        :scrollbar-always-on="props.tableScrollbarAlwaysOn"
        :show-overflow-tooltip="props.tableShowOverflowTooltip"
        :flexible="props.tableFlexible"
        @select="handleTableSelect"
        @selection-change="handleTableSelectionChange"
        @select-all="handleTableSelectAll"
        @cell-mouse-enter="handleTableCellMouseEnter"
        @cell-mouse-leave="handleTableCellMouseLeave"
        @cell-click="handleTableCellClick"
        @cell-dblclick="handleTableCellDblclick"
        @cell-contextmenu="handleTableCellContextmenu"
        @row-click="handleTableRowClick"
        @row-contextmenu="handleTableRowContextmenu"
        @row-dblclick="handleTableRowDblclick"
        @header-click="handleTableHeaderClick"
        @header-contextmenu="handleTableHeaderContextmenu"
        @sort-change="handleTableSortChange"
        @filter-change="handleTableFilterChange"
        @current-change="handleTableCurrentChange"
        @header-dragend="handleTableHeaderDragend"
        @expand-change="handleTableExpandChange"
        @scroll="handleTableScroll"
    >
        <template v-for="(column, index) in props.tableHeader" :key="index">
            <template v-if="column.children && column.children.length > 0">
                <el-table-column
                    v-if="!column.columnHidden"
                    :type="column.columnType"
                    :prop="column.columnProp"
                    :index="column.columnIndex"
                    :label="column.columnLabel"
                    :column-key="column.columnKey"
                    :width="column.columnWidth"
                    :min-width="column.columnMinWidth"
                    :fixed="column.columnFixed"
                    :render-header="column.columnRenderHeader"
                    :sortable="column.columnSortable"
                    :sort-method="column.columnSortMethod"
                    :sort-by="column.columnSortBy"
                    :sort-orders="column.columnSortOrders"
                    :resizable="column.columnResizable"
                    :formatter="column.columnFormatter"
                    :show-overflow-tooltip="column.columnShowOverflowTooltip"
                    :align="column.columnAlign"
                    :header-align="column.columnHeaderAlign"
                    :class-name="column.columnClassName"
                    :label-class-name="column.columnLabelClassName"
                    :selectable="column.columnSelectable"
                    :reserve-selection="column.columnReserveSelection"
                    :filters="column.columnFilters"
                    :filter-placement="column.columnFilterPlacement"
                    :filter-class-name="column.columnFilterClassName"
                    :filter-multiple="column.columnFilterMultiple"
                    :filter-method="column.columnFilterMethod"
                    :filtered-value="column.columnFilteredValue"
                >
                    <table-column
                        v-for="(item, idx) in column.children"
                        :key="idx"
                        :columnData="item"
                    >
                        <template #default="scope">
                            <slot
                                :name="column.columnSlot"
                                :scope="handledScope(scope)"
                            >
                            </slot>
                        </template>
                    </table-column>
                </el-table-column>
            </template>
            <template v-else>
                <template v-if="column.columnSlot || column.headerSlot">
                    <el-table-column
                        v-if="!column.columnHidden"
                        :type="column.columnType"
                        :prop="column.columnProp"
                        :index="column.columnIndex"
                        :label="column.columnLabel"
                        :column-key="column.columnKey"
                        :width="column.columnWidth"
                        :min-width="column.columnMinWidth"
                        :fixed="column.columnFixed"
                        :render-header="column.columnRenderHeader"
                        :sortable="column.columnSortable"
                        :sort-method="column.columnSortMethod"
                        :sort-by="column.columnSortBy"
                        :sort-orders="column.columnSortOrders"
                        :resizable="column.columnResizable"
                        :formatter="column.columnFormatter"
                        :show-overflow-tooltip="
                            column.columnShowOverflowTooltip
                        "
                        :align="column.columnAlign"
                        :header-align="column.columnHeaderAlign"
                        :class-name="column.columnClassName"
                        :label-class-name="column.columnLabelClassName"
                        :selectable="column.columnSelectable"
                        :reserve-selection="column.columnReserveSelection"
                        :filters="column.columnFilters"
                        :filter-placement="column.columnFilterPlacement"
                        :filter-class-name="column.columnFilterClassName"
                        :filter-multiple="column.columnFilterMultiple"
                        :filter-method="column.columnFilterMethod"
                        :filtered-value="column.columnFilteredValue"
                    >
                        <template #default="scope" v-if="column.columnSlot">
                            <slot
                                :name="column.columnSlot"
                                :scope="handledScope(scope)"
                            >
                            </slot>
                        </template>
                        <template #header v-if="column.headerSlot">
                            <slot :name="column.headerSlot"> </slot>
                        </template>
                    </el-table-column>
                </template>
                <template v-else>
                    <el-table-column
                        v-if="!column.columnHidden"
                        :type="column.columnType"
                        :prop="column.columnProp"
                        :index="column.columnIndex"
                        :label="column.columnLabel"
                        :column-key="column.columnKey"
                        :width="column.columnWidth"
                        :min-width="column.columnMinWidth"
                        :fixed="column.columnFixed"
                        :render-header="column.columnRenderHeader"
                        :sortable="column.columnSortable"
                        :sort-method="column.columnSortMethod"
                        :sort-by="column.columnSortBy"
                        :sort-orders="column.columnSortOrders"
                        :resizable="column.columnResizable"
                        :formatter="column.columnFormatter"
                        :show-overflow-tooltip="
                            column.columnShowOverflowTooltip
                        "
                        :align="column.columnAlign"
                        :header-align="column.columnHeaderAlign"
                        :class-name="column.columnClassName"
                        :label-class-name="column.columnLabelClassName"
                        :selectable="column.columnSelectable"
                        :reserve-selection="column.columnReserveSelection"
                        :filters="column.columnFilters"
                        :filter-placement="column.columnFilterPlacement"
                        :filter-class-name="column.columnFilterClassName"
                        :filter-multiple="column.columnFilterMultiple"
                        :filter-method="column.columnFilterMethod"
                        :filtered-value="column.columnFilteredValue"
                    />
                </template>
            </template>
        </template>
    </el-table>
</template>
<script setup>
import { ref, defineOptions, defineEmits } from 'vue'
defineOptions({ name: 'base-table' })
const tableRefMap = ref({})
const props = defineProps({
    /**
     * 表格id
     * @type String
     * @value String
     */
    tableId: {
        type: String,
        required: false,
        default: () => {
            return 'table' + Math.random().toString(36).substring(2)
        }
    },
    /**
     * 表格高度
     * @type String
     * @value String
     */
    tableHeight: {
        type: [String, Number],
        required: false,
        default: () => {
            return null
        }
    },
    /**
     * 表格数据(必传)
     * @type Array
     * @value Array
     */
    tableData: {
        type: Array,
        required: true,
        default: () => []
    },
    /**
     * 表头数据数据(必传)
     * @type Array
     * @value Array
     */
    tableHeader: {
        type: Array,
        required: true,
        default: () => []
    },
    /**
     * 表格是否带有纵向边框
     * @type Boolean/String
     * @value Boolean/String
     */
    tableBorder: {
        type: Boolean,
        required: false,
        default: () => {
            return false
        }
    },
    /**
     * 表格尺寸
     * @type String
     * @value 	'' | 'large' | 'default' | 'small'
     */
    tableSize: {
        type: String,
        required: false,
        default: () => {
            return null
        }
    },
    /**
     * 列的宽度是否自撑开
     */
    tableFit: {
        type: Boolean,
        required: false,
        default: () => {
            return true
        }
    },
    /**
     * 表格是否带有斑马纹
     * @type Boolean/String
     * @value Boolean/String
     */
    tableStripe: {
        type: Boolean,
        required: false,
        default: () => {
            return false
        }
    },
    /**
     * 渲染树形表格的配置选项
     * @type Object
     * @value { hasChildren: 'hasChildren', children: 'children' }
     */
    tableTreeProps: {
        type: Object,
        required: false,
        default: () => {
            return {
                hasChildren: 'hasChildren',
                children: 'children'
            }
        }
    },
    /**
     * 行数据的 Key，用来优化 Table 的渲染；用于判断表格行数据唯一性的标识字段；
     * 当需要指定表格多选默认选中、单选选中、树形结构表格时 需要用到此属性
     * 默认值为 id
     * @type String
     * @value String
     */
    tableRowKey: {
        type: [Function, String],
        required: false,
        default: () => {
            return 'id'
        }
    },
    /**
     * 是否开启高亮当前行
     * @type Boolean/String
     * @value Boolean/String
     */
    tableHighlightCurrentRow: {
        type: Boolean,
        required: false,
        default: () => {
            return false
        }
    },
    /**
     * 是否显示加载中效果
     * @type Boolean/String
     * @value Boolean/String
     */
    tableLoading: {
        type: Boolean,
        required: false,
        default: () => {
            return false
        }
    },
    /**
     * 是否默认展开所有行，当 Table 包含展开行存在或者为树形表格时有效
     * @type Boolean/String
     * @value Boolean/String
     */
    tableDefaultExpandAll: {
        type: Boolean,
        required: false,
        default: () => {
            return false
        }
    },
    /**
     * 行样式
     * @type Function/String
     * @value Function
     */
    tableRowClassName: {
        type: [Function, String],
        required: false,
        default: () => {
            return null
        }
    },
    /**
     * 表格最大高度
     * @type String/Number
     * @value String
     */
    tableMaxHeight: {
        type: [String, Number],
        required: false,
        default: () => {
            return null
        }
    },
    /**
     * 是否显示表头
     * @type Boolean
     * @value Boolean
     */
    tableShowHeader: {
        type: Boolean,
        required: false,
        default: () => {
            return true
        }
    },
    /**
     * 默认选中当前行
     * @type String
     * @value String
     */
    tableCurrentRowKey: {
        type: [String, Number],
        required: false,
        default: () => {
            return null
        }
    },
    /**
     * 行样式
     * @type Function/Object
     * @value Function
     */
    tableRowStyle: {
        type: [Function, Object],
        required: false,
        default: () => {
            return null
        }
    },
    /**
     * 单元格样式
     * @type Function/String
     * @value Function
     */
    tableCellClassName: {
        type: [Function, String],
        required: false,
        default: () => {
            return null
        }
    },
    /**
     * 单元格样式
     * @type Function
     * @value Function
     */
    tableCellStyle: {
        type: [Function, Object],
        required: false,
        default: () => {
            return null
        }
    },
    /**
     * 表头单元格样式
     * @type Function
     * @value Function
     */
    tableHeaderRowClassName: {
        type: [Function, String],
        required: false,
        default: () => {
            return null
        }
    },
    /**
     * 表头单元格样式
     * @type Function
     * @value Function
     */
    tableHeaderRowStyle: {
        type: [Function, Object],
        required: false,
        default: () => {
            return null
        }
    },
    /**
     * 表头单元格样式
     * @type Function
     * @value Function
     */
    tableHeaderCellClassName: {
        type: [Function, String],
        required: false,
        default: () => {
            return null
        }
    },
    /**
     * 表头单元格样式
     * @type Function
     * @value Function
     */
    tableHeaderCellStyle: {
        type: [Function, Object],
        required: false,
        default: () => {
            return null
        }
    },
    /**
     * 空数据时显示的文本内容， 也可以通过 #empty 设置
     * @type String
     * @value String
     */
    tableEmptyText: {
        type: String,
        required: false,
        default: () => {
            return '暂无数据'
        }
    },
    /**
     * 可以通过该属性设置 Table 目前的展开行，需要设置 row-key 属性才能使用，该属性为展开行的 keys 数组。
     * @type Array
     * @value Array
     */
    tableExpandRowKeys: {
        type: Array,
        required: false,
        default: () => {
            return []
        }
    },
    /**
     * 默认的排序列的 prop 和顺序。 它的 prop 属性指定默认的排序的列，order 指定默认排序的顺序
     * @type Object
     * @value { prop: 'id', order: 'descending' }
     */
    tableDefaultSort: {
        type: Object,
        required: false,
        default: () => {
            return {}
        }
    },
    /**
     * 溢出的 tooltip 的 effect
     * @type String
     * @value light/dark
     */
    tableTooltipEffect: {
        type: String,
        required: false,
        default: () => {
            return 'light'
        }
    },
    /**
     * 溢出 tooltip 的选项，参见下述 tooltip 组件
     * @type Object
     * @value Object
     */
    tableTooltipOptions: {
        type: Object,
        required: false,
        default: () => {
            return null
        }
    },
    /**
     * 是否在表尾显示合计行
     * @type Boolean/String
     * @value Boolean/String
     */
    tableShowSummary: {
        type: Boolean,
        required: false,
        default: () => {
            return false
        }
    },
    /**
     * 显示摘要行第一列的文本
     * @type String
     * @value String
     */
    tableSumText: {
        type: String,
        required: false,
        default: () => {
            return '合计'
        }
    },
    /**
     * 自定义的合计计算方法
     * @type Function
     * @value Function
     */
    tableSummaryMethod: {
        type: Function,
        required: false,
        default: () => {
            return undefined
        }
    },
    /**
     * 合并行或列的计算方法
     * @type Function
     * @value Function
     */
    tableSpanMethod: {
        type: Function,
        required: false,
        default: () => {
            return undefined
        }
    },
    /**
     * 在多选表格中，当仅有部分行被选中时，点击表头的多选框时的行为。 若为 true，则选中所有行；若为 false，则取消选择所有行
     * @type Boolean/String
     * @value Boolean/String
     */
    tableSelectOnIndeterminate: {
        type: Boolean,
        required: false,
        default: () => {
            return false
        }
    },
    /**
     * 展示树形数据时，树节点的缩进
     * @type Number
     * @value Number
     */
    tableIndent: {
        type: Number,
        required: false,
        default: () => {
            return 0
        }
    },
    /**
     * 是否懒加载子节点数据
     * @type Boolean/String
     * @value Boolean/String
     */
    tableLazy: {
        type: Boolean,
        required: false,
        default: () => {
            return false
        }
    },
    /**
     * 加载子节点数据的函数，lazy 为 true 时生效
     * @type Function
     * @value Function
     */
    tableLoad: {
        type: Function,
        required: false,
        default: () => {
            return undefined
        }
    },
    /**
     * 设置表格单元、行和列的布局方式
     * @type String
     * @value auto/fixed
     */
    tableTableLayout: {
        type: String,
        required: false,
        default: () => {
            return 'fixed'
        }
    },
    /**
     * 总是显示滚动条
     * @type Boolean/String
     * @value Boolean/String
     */
    tableScrollbarAlwaysOn: {
        type: Boolean,
        required: false,
        default: () => {
            return false
        }
    },
    /**
     * 是否隐藏额外内容并在单元格悬停时使用 Tooltip 显示它们。这将影响全部列的展示，详请参考tooltip-options
     * @type Boolean/String
     * @value Boolean/String
     */
    tableShowOverflowTooltip: {
        type: [Boolean, Object],
        required: false,
        default: () => {
            return false
        }
    },
    /**
     * 确保主轴的最小尺寸，以便不超过内容
     * @type Boolean/String
     * @value Boolean/String
     */
    tableFlexible: {
        type: Boolean,
        required: false,
        default: () => {
            return false
        }
    }
})
import tableColumn from './tableColumn.vue'
const emit = defineEmits([
    'Select',
    'SelectionChange',
    'SelectAll',
    'CellMouseEnter',
    'CellMouseLeave',
    'CellClick',
    'CellDblclick',
    'CellContextmenu',
    'RowClick',
    'RowDblclick',
    'RowContextmenu',
    'HeaderClick',
    'HeaderContextmenu',
    'SortChange',
    'FilterChange',
    'CurryChange',
    'HeaderDragend',
    'ExpandChange',
    'Scroll'
])
/** 动态设置Table Ref */
const handleSetTableMap = (el) => {
    if (el) {
        tableRefMap.value[`${props.tableId}`] = el
    }
}
/**
 * 对作用域插槽数据处理
 * 取出多层嵌套数据中的最里面一层数据 便于开发人员取到数据
 * @params 下一级组件中绑定的作用域插槽数据
 */
const handledScope = (scope) => {
    while (
        scope.scope &&
        Object.prototype.toString.call(scope.scope) === '[object Object]'
    ) {
        scope = scope.scope
    }
    return scope || {}
}
// 表格单选选中
const handleTableSelect = (row) => {
    emit('Select', row)
}

// 当用户手动勾选全选 Checkbox 时触发的事件
const handleTableSelectAll = (data) => {
    emit('SelectAll', data)
}
// 多选表格选中发生改变
const handleTableSelectionChange = (data) => {
    emit('SelectionChange', data)
}

// 当单元格 hover 进入时会触发该事件
const handleTableCellMouseEnter = (data) => {
    emit('CellMouseEnter', data)
}
// 当单元格 hover 退出时会触发该事件
const handleTableCellMouseLeave = (data) => {
    emit('CellMouseLeave', data)
}

// 当某个单元格被点击时会触发该事件
const handleTableCellClick = (data) => {
    emit('CellClick', data)
}
// 当某个单元格被双击击时会触发该事件
const handleTableCellDblclick = (data) => {
    emit('CellDblclick', data)
}
// 当某个单元格被鼠标右键点击时会触发该事件
const handleTableCellContextmenu = (data) => {
    emit('CellContextmenu', data)
}

// 当某一行被点击时会触发该事件
const handleTableRowClick = (data) => {
    emit('RowClick', data)
}
// 当某一行被点击时会触发该事件
const handleTableRowContextmenu = (data) => {
    emit('RowContextmenu', data)
}

// 当某一行被双击时会触发该事件
const handleTableRowDblclick = (data) => {
    emit('RowDblclick', data)
}
// 当某一列的表头被点击时会触发该事件
const handleTableHeaderClick = (data) => {
    emit('HeaderClick', data)
}

// 当某一列的表头被鼠标右键点击时触发该事件
const handleTableHeaderContextmenu = (data) => {
    emit('HeaderContextmenu', data)
}
// 表格排序发生改变
const handleTableSortChange = (data) => {
    emit('SortChange', data)
}
// column 的 key， 如果需要使用 filter-change 事件，则需要此属性标识是哪个 column 的筛选条件
const handleTableFilterChange = (data) => {
    emit('FilterChange', data)
}

// 当表格的当前行发生变化的时候会触发该事件，如果要高亮当前行，请打开表格的 highlight-current-row 属性
const handleTableCurrentChange = (data) => {
    emit('CurryChange', data)
}
// 当拖动表头改变了列的宽度的时候会触发该事件
const handleTableHeaderDragend = (data) => {
    emit('HeaderDragend', data)
}

// 当用户对某一行展开或者关闭的时候会触发该事件（展开行时，回调的第二个参数为 expandedRows；树形表格时第二参数为 expanded）
const handleTableExpandChange = (data) => {
    emit('ExpandChange', data)
}
// 当用户对某一行展开或者关闭的时候会触发该事件（展开行时，回调的第二个参数为 expandedRows；树形表格时第二参数为 expanded）
const handleTableScroll = (data) => {
    emit('Scroll', data)
}

// 用于多选表格，清空用户的选择
const clearSelection = () => {
    tableRefMap.value[`${props.id}`].clearSelection()
}
// 返回选中的行
const getSelectionRows = () => {
    return tableRefMap.value[`${props.id}`].getSelectionRows()
}
// 切换选中的行
const toggleRowSelection = (
    row,
    selected,
    ignoreSelectable
) => {
    tableRefMap.value[`${props.id}`].toggleRowSelection(
        row,
        selected,
        ignoreSelectable
    )
}
// 切换全选
const toggleAllSelection = () => {
    tableRefMap.value[`${props.id}`].toggleAllSelection()
}
// 切换树形表格行展开/收起
const toggleRowExpansion = (row, expanded) => {
    tableRefMap.value[`${props.id}`].toggleRowExpansion(row, expanded)
}
// 切换单选表格固定行选中/取消
const setCurrentRow = (row, expanded) => {
    tableRefMap.value[`${props.id}`].setCurrentRow(row, expanded)
}
// 用于清空排序条件，数据会恢复成未排序的状态
const clearSort = () => {
    tableRefMap.value[`${props.id}`].clearSort()
}
// 传入由columnKey 组成的数组以清除指定列的过滤条件。 如果没有参数，清除所有过滤器
const clearFilter = (columnKey) => {
    tableRefMap.value[`${props.id}`].clearFilter(columnKey)
}
// 对 Table 进行重新布局。 当表格可见性变化时，您可能需要调用此方法以获得正确的布局
const doLayout = () => {
    tableRefMap.value[`${props.id}`].doLayout()
}
// 手动排序表格。 参数 prop 属性指定排序列，order 指定排序顺序。
const sort = (prop, order) => {
    tableRefMap.value[`${props.id}`].sort(prop, order)
}
// 滚动到一组特定坐标
const scrollTo = (options, yCoord) => {
    tableRefMap.value[`${props.id}`].scrollTo(options, yCoord)
}
// 设置垂直滚动位置
const setScrollTop = (top) => {
    tableRefMap.value[`${props.id}`].setScrollTop(top)
}
// 设置水平滚动位置
const setScrollLeft = (left) => {
    tableRefMap.value[`${props.id}`].setScrollLeft(left)
}
// 获取表列的 context
const columns = () => {
    return tableRefMap.value[`${props.id}`].columns()
}
// 适用于 lazy Table, 需要设置 rowKey, 更新 key children
const updateKeyChildren = (key, data) => {
    tableRefMap.value[`${props.id}`].updateKeyChildren(key, data)
}
defineExpose({
    clearSelection,
    getSelectionRows,
    toggleRowSelection,
    toggleAllSelection,
    toggleRowExpansion,
    setCurrentRow,
    clearSort,
    clearFilter,
    doLayout,
    sort,
    scrollTo,
    setScrollTop,
    setScrollLeft,
    columns,
    updateKeyChildren
})
</script>
<style lang="scss" scoped></style>
